/// 闭包相关，此处对应的只是点有
/// 闭包类型，move, clone


pub fn main() {
    // 声明一个闭包，|| 开头，中间是参数声明
    let c1 = || {
        println!("abc");
    };

    c1();
    // 最后的{},当只有一个语句的时候，是可以省略的
    let c2 = || println!("abc");
    c2();

    // 这个例子表示传参, 变量使用所有权系统，
    let name =  "abc";
    let c3 = |name :&str| println!("{}", name);
    c3(name);
    println!("此处验证，拥有clone特性的闭包已经使用了一个变量，还能不能再次使用，{}", name);


    // 一开始也说了闭包是有类型的，就是根据变量的权限来判断的
    // 此时的变量不是说明的闭包参数，是闭包使用了当前所在域的其他变量
    // 如果使用了变量的所有权，则是FnOnce类型，如果使用了mut引用，则是FnMut类型，只是引用则是Fn
    #[derive(Debug)]
    struct Ctype;
    let name = Ctype;
    let c4 = || println!("{:?}", &name);
    c4();
    println!("此处验证，没使用clone特性的闭包已经使用了一个变量，还能不能再次使用，{:?}", name);

    // c5 把name的所有权移动到了闭包内
    let c5 = move || println!("{:?}", name);
    c5();
    // c5可以调用多次，因为name已经在闭包的作用域内
    c5();
    // 下面这句如果放开就会报所有权错误
    // println!("此处验证，没使用clone特性的闭包已经使用了一个变量，还能不能再次使用，{:?}", name);


}

trait Ta {
    fn test() {
        println!("test");
    }
}

#[derive(Clone)]
struct A;

impl Ta for A {}

struct B {
    a:A
}
impl Ta for B {}


/// Clone表示的不是I，指的是F这个类型，可以理解为 F： (Fn_>I)+Clone,关于闭包是不是可以Clone的，就要看闭包中的变量是否实现了Clone
fn f1<F:Fn()->I+Clone, I:Ta>( f:F) {
    f();
}

#[cfg(test)]
mod test {

    use super::*;

    #[test]
    fn test() {

        // clone函数不会自动调用，如果我们不使用a.clone()，则cs是个fnOnce类型，返回了a的所有权
        let a  = A;
        let cs = || a.clone();
        f1(cs);

        // 如果一个闭包中创建一个没有实现Clone的可以实现Fn clone吗
        let cs =  || B {a:a.clone()};
        let cs2 = cs.clone();
        f1(cs);
        f1(cs2);
        // 通过例子可以证明，B没有实现Clone，

    }
}